package io.bwqueen.nettylearn;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.URLEncoder;
import java.util.concurrent.CountDownLatch;

/**
 * 一个SocketClientRequestThread
 *
 * @author dev
 */
@Slf4j
public class SocketClientRequestThread implements Runnable {

    /**
     * CountDownLatch典型的用法是将一个程序分为n个互相独立的可解决任务，并创建值为n的CountDownLatch。
     * 当每一个任务完成时，都会在这个锁存器上调用countDown，等待问题被解决的任务调用这个锁存器的await，
     * 将他们自己拦住，直至锁存器计数结束
     */
    private CountDownLatch countDownLatch;

    /**
     * 这个线程的编号
     */
    private Integer clientIndex;

    /**
     * countDownLatch是java提供的同步计数器
     * 当计数器的数值减为零时，所以受其影响而等待的线程都会被激活。这样保证模拟并发请求的真实性
     */
    public SocketClientRequestThread(CountDownLatch countDownLatch, Integer clientIndex) {
        this.countDownLatch = countDownLatch;
        this.clientIndex = clientIndex;
    }

    public void run() {
        Socket socket = null;
        OutputStream clientRequest = null;
        InputStream clientResponse = null;

        try {
            socket = new Socket("localhost", 83);
            clientRequest = socket.getOutputStream();
            clientResponse = socket.getInputStream();

            // 等待，知道SocketClientDaemon完成所有线程的启动，然后所有线程一起发请求
            this.countDownLatch.await();

            // 发送请求信息
            clientRequest.write(URLEncoder.encode(
                    String.format("这是第{}个客户端的请求11", this.clientIndex), "UTF-8").getBytes()
            );
            clientRequest.flush();
            clientRequest.write(URLEncoder.encode(
                    String.format("这是第{}个客户端的请求22", this.clientIndex), "UTF-8").getBytes()
            );

            // 在这里等待，直到服务器返回信息
            log.info("第{}个客户端的请求发送完成，等待服务器返回信息", this.clientIndex);
            int maxLen = 1024;
            byte[] contextBytes = new byte[maxLen];
            int realLen;
            String message = "";
            // 程序执行到这里，会一直等待服务器返回信息（注意，前提是in和out都不能close，如果close了就收不到服务器的反馈了）
            while ((realLen = clientResponse.read(contextBytes, 0, maxLen)) != -1) {
                message += new String(contextBytes, 0, realLen);
            }
            log.info("接收到来自服务器的信息: {}", message);
        } catch (Exception e) {
            log.error("error", e);
        } finally {
            try {
                if (clientRequest != null) {
                    clientRequest.close();
                }
                if (clientResponse != null) {
                    clientResponse.close();
                }
            } catch (IOException e) {
                log.error("error", e);
            }
        }
    }
}
